#include "Image.h"
#include <cmath>
#include <fstream>

Image::Image()
{
	raster = NULL;
}

Image::Image(int width, int height)
{
	nx = width;
	ny = height;

	raster = new rgb*[nx];
	for (int i = 0; i < nx; i++)
		raster[i] = new rgb[ny];
}

Image::Image(int width, int height, rgb background)
{
	nx = width;
	ny = height;

	raster = new rgb*[nx];
	for (int i = 0; i < nx; i++)
	{	
		raster[i] = new rgb[ny];
		for (int j = 0; j < ny; j++)
			raster[i][j] = background;
	}
}

bool Image::set(int x, int y, const rgb &color)
{
	if (x < 0 || x >= nx || y < 0 || y >= ny) return false;

	raster[x][y] = color;
	return true;
}

bool Image::get(int x, int y, rgb &color, float scale /* = 1.0f */)
{
	if (x < 0 || x >= nx || y < 0 || y >= ny) return false;

	color = raster[x][y] * scale;
	if (color.r() < 0.0f) color.setRed(0.0f);
	if (color.r() > scale) color.setRed(scale);

	if (color.g() < 0.0f) color.setGreen(0.0f);
	if (color.g() > scale) color.setGreen(scale);

	if (color.b() < 0.0f) color.setBlue(0.0f);
	if (color.b() > scale) color.setBlue(scale);
	return true;
}

rgb Image::getPixel(int x, int y)
{
	return raster[x][y];
}

void Image::gammaCorrect(float gamma)
{
	rgb color;
	float power = 1.0f / gamma;
	for (int i = 0; i < nx; i++)
	{
		for (int j = 0; j < ny; j++)
		{
			color = raster[i][j];
			raster[i][j] = rgb(pow(color.r(), power), 
				pow(color.g(), power), 
				pow(color.b(), power));
		}
	}
}

void Image::writePPM(ostream& out)
{
	//	PPM file format
	//	header
	out << "P6\n";
	out << nx << ' ' << ny << '\n';
	out << "255\n";

	//	0-255 rgb values

	//	coords in image:
	//	origin: lower-left
	//	x: horizontal
	//	y: vertical
	//	e.g.:
	//	height:3
	//	width:4
	//	[02][12][22][32]
	//	[01][11][21][31]
	//	[00][10][20][30]
	
	//	storage in PPM:
	//	store each row from top to bottom
	//	in each row, store it from left to right
	//	e.g.:
	//	[02][12][22][32][01][11][21][31][00][10][20][30]

	unsigned int ired, igreen, iblue;
	unsigned char red, green, blue;

	for (int i = ny - 1; i >= 0; i--)
	{
		for (int j = 0; j < nx; j++)
		{
			ired = (unsigned int)(raster[j][i].r() * 256);
			igreen = (unsigned int)(raster[j][i].g() * 256);
			iblue = (unsigned int)(raster[j][i].b() * 256);
			if (ired > 255) ired = 255;
			if (igreen > 255) igreen = 255;
			if (iblue > 255) iblue = 255;
			red = (unsigned char)ired;
			green = (unsigned char)igreen;
			blue = (unsigned char)iblue;
			out << red << green << blue;
		}
	}
}

void Image::readPPM(string file_name)
{
	ifstream fin;
	fin.open(file_name);

	char ch, type;
	int num;

	fin.get(ch);	//P
	fin.get(type);	//6
	fin >> nx >> ny >> num;	//	width height maxcolor

	raster = new rgb*[nx];
	for (int i = 0; i < nx; i++)
		raster[i] = new rgb[ny];

	unsigned char red, green, blue;
	for (int i = ny - 1; i >= 0; i--)
	{
		for (int j = 0; j < nx; j++)
		{
			fin >> red >> green >> blue;
			raster[j][i] = rgb((float)red / 256, 
				(float)green / 256,
				(float)blue / 256);
		}
	}
	fin.close();
}

Image::~Image()
{
	if (raster)
	{
		for (int i = 0; i < nx; i++)
		{
			if (raster[i])
				delete []raster[i];
		}
		delete []raster;
	}
}

int Image::getHeight()
{
	return ny;
}

int Image::getWidth()
{
	return nx;
}